// Food Clerk Agent
//
// This function represents the logic and activities of a ticket clerk in the movie theater simulation.
// This function will be forked onto a thread during initialization.
//

#include "FoodClerkAgent.h"
#include "globalsExtern.cc"
#include "utility.h"

void FoodClerkAgentExecute(int arg) {
	// Food Clerk Agent local data goes here
	int FoodClerkID = arg;
	int numPopcornRequested;
	int numSodaRequested;
	int totalPrice;
	int pricePaid;

	// Food Clerk Agent running code should go here.
	DEBUG('F', "%s: Thread now running.\n", currentThread->getName());
	
	foodClerkCustomerLock[FoodClerkID]->Acquire();
	foodClerkCondition[FoodClerkID]->Wait(foodClerkCustomerLock[FoodClerkID]);
	// Loop Invariant - Finished with last customer, starting a new conversation.
	while (true) {
	   // Wake up the next customer in our line and tell him to approach.
	   foodLineSelectionLock->Acquire();
	   foodLineSelectionCondition[FoodClerkID]->Signal(foodLineSelectionLock);
	   foodLineSelectionLock->Release();
	   foodClerkCondition[FoodClerkID]->Wait(foodClerkCustomerLock[FoodClerkID]);

	   // At this point the customer is waiting at our kiosk and has
	   // listed how many tickets they need.
	   totalsLock->Acquire();
	   totalsWhiteboard->incrementFoodRevenue(FoodClerkID, totalPrice);
	   
	   // Ok to sell the tickets, updating "availible tickets"
	   //totalsWhiteboard->setAvailableTickets(totalsWhiteboard->getAvailableTickets() - ticketClerkCustomerWhiteboard[TicketClerkID]->getNumTickets());
	   // Update stats on the totals lock (num sold, revenue, ect)
	   totalsLock->Release();
	   
	   
	   // Post price to whiteboard
		numPopcornRequested = foodClerkCustomerWhiteboard[FoodClerkID]->getNumPopcorn();
		numSodaRequested = foodClerkCustomerWhiteboard[FoodClerkID]->getNumSoda();
		totalPrice = (numPopcornRequested*5) + (numSodaRequested*4);
		foodClerkCustomerWhiteboard[FoodClerkID]->setTotalPrice(totalPrice);
		DEBUG('R',"%s has an order for %d popcorn and %d soda. The cost is %d.\n",currentThread->getName(),numPopcornRequested,numSodaRequested, totalPrice);
		DEBUG('F', "%s: Requesting $%d for the food. Woke up Customer.\n", currentThread->getName(), totalPrice);
		foodCustomerCondition[FoodClerkID]->Signal(foodClerkCustomerLock[FoodClerkID]);
		foodClerkCondition[FoodClerkID]->Wait(foodClerkCustomerLock[FoodClerkID]);
		
		// Customer responded with they amount they will pay and woke us up.
		pricePaid = foodClerkCustomerWhiteboard[FoodClerkID]->getMoneyGiven();
		if (pricePaid != totalPrice) {
			DEBUG('F', "%s: ERROR: Customer did not pay correct price.\n", currentThread->getName());
		}
		DEBUG('R', "%s has been paid for the order.\n",currentThread->getName());
		DEBUG('F', "%s: Woke up customer.\n", currentThread->getName());
		foodCustomerCondition[FoodClerkID]->Signal(foodClerkCustomerLock[FoodClerkID]);
		foodClerkCondition[FoodClerkID]->Wait(foodClerkCustomerLock[FoodClerkID]);

	   // At this point the customer has taken his food and left.
	   ClearFoodClerkCustomerWhiteboard(FoodClerkID);

	   // Need to check if our line is empty or not
	   // If it is empty we should sleep until a customer enters our line
	   // and awakens us. If a customer is there we should return to start
	   // of the loop.
	   foodLineSelectionLock->Acquire();
	   if (foodLineSelectionWhiteboard->getLineLength(FoodClerkID) == 0) {
		  DEBUG('R', "%s: has no one in line. I am available for a customer.\n", currentThread->getName());
		  foodLineSelectionLock->Release();
		  // There is no one in our line, sleeping
		  foodClerkCondition[FoodClerkID]->Wait(foodClerkCustomerLock[FoodClerkID]);
	   }
	   else {
		  // Thre is someone in my line, calling next customer
		  DEBUG('R', "%s has a line length %d and is signaling a customer.\n", currentThread->getName(),foodLineSelectionWhiteboard->getLineLength(FoodClerkID));
		  foodLineSelectionLock->Release();
	   }
	}
}

void ClearFoodClerkCustomerWhiteboard(int FoodClerkID) {
    DEBUG('F', "%s: Clearing whiteboard.\n", currentThread->getName());
	foodClerkCustomerWhiteboard[FoodClerkID]->setNumPopcorn(0);
	foodClerkCustomerWhiteboard[FoodClerkID]->setNumSoda(0);
	foodClerkCustomerWhiteboard[FoodClerkID]->setTotalPrice(0);
	foodClerkCustomerWhiteboard[FoodClerkID]->setMoneyGiven(0);
}
